package org.dctmcommons;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.common.DfException;

/**
 * Extends DctmCommons to provide basic testing support.
 * @author Mark Davidson
 */
public class DctmCommonsTestContext extends DctmCommons {

	/** Serial id. */
	private static final long serialVersionUID = 4884131902799912016L;

	/** The session. */
	private IDfSession _session = null;
	
	/** The session manager. */
	private IDfSessionManager _manager = null;
	
	/** The name of the default properties file. */
    public static final String DEFAULT_PROPERTIES_FILE = "/test.properties";

    /** The name of the local properties file. */
    public static final String LOCAL_PROPERTIES_FILE = "/local.test.properties";

    /** The prefix for the parameter keys. */
    public static final String KEY_PREFIX = "DCTM_";

    /** Key for the username parameter. */
    public static final String KEY_USERNAME = KEY_PREFIX + "USERNAME";

    /** Key for the password parameter. */
    public static final String KEY_PASSWORD = KEY_PREFIX + "PASSWORD";

    /** Key for the domain parameter. */
    public static final String KEY_DOMAIN = KEY_PREFIX + "DOMAIN";

    /** Key for the repository parameter. */
    public static final String KEY_REPOSITORY = KEY_PREFIX + "REPOSITORY";

    /** The default username. */
    public static final String DEFAULT_USERNAME = "dmadmin";

    /** The default password. */
    public static final String DEFAULT_PASSWORD = "dmadmin";

    /** The default domain. */
    public static final String DEFAULT_DOMAIN = null;

    /** The default repository. */
    public static final String DEFAULT_REPOSITORY = "documentum";

    /** The test properties. */
    private Properties properties = null;

    /**
     * Default constructor
     */
    protected DctmCommonsTestContext() {
    	initConfig();
    }
    
    /**
     * Factory method.
     * @return The DctmCommonsTestContext instance
     */
    public static DctmCommonsTestContext getInstance() {
    	return new DctmCommonsTestContext();
    }
	
    /**
     * Releases the session.
     */
    public void releaseSession() {
    	session.releaseSession(_session);
    	_session = null;
    }
    
	/**
	 * Gets a session, using a cached one if available.
	 * @param repository The repository name
	 * @return The session
	 * @throws DfException The repository exception
	 */
	public IDfSession getSession() throws DfException {
		if (_session == null) {
			_session = getSessionManager().getSession(getRepository());
		}
		
		return _session;
	}
	
	/**
	 * Gets a session manager, using a cached one if available.
	 * @return The session manager
	 * @throws DfException The repository exception
	 */
	private IDfSessionManager getSessionManager() throws DfException {
		if (_manager == null) {
			initConfig();
			_manager = session.createSessionManager(getRepository(),
													getUsername(),
													getPassword(),
													getDomain());
		}
		
		return _manager;
	}
	
    /**
     * Initialises the properties.
     */
    protected void initConfig() {
        properties = new Properties();

        // set some default properties
        properties.setProperty(KEY_USERNAME, DEFAULT_USERNAME);
        properties.setProperty(KEY_PASSWORD, DEFAULT_PASSWORD);
        properties.setProperty(KEY_REPOSITORY,  DEFAULT_REPOSITORY);
        
        // load override properties
        loadPropertiesFile(DEFAULT_PROPERTIES_FILE);
        loadPropertiesFile(LOCAL_PROPERTIES_FILE);
        loadEnvironmentVariables();
        loadSystemProperties();
    }

    /**
     * Loads properties from a properties file on the classpath.
     * @param filename The filename
     */
    public void loadPropertiesFile(final String filename) {
        final Properties extProps = new Properties();
        final InputStream in = getClass().getResourceAsStream(filename);
        if (in != null) {
            try {
                extProps.load(in);
                in.close();
                loadProperties(extProps);
            } catch (IOException e) {
                System.out.println("Failed to load properties file: " +
                                        filename);
            }
        }
    }

    /**
     * Loads the test properties from system properties.
     */
    public void loadSystemProperties() {
        loadProperties(System.getProperties());
    }

    /**
     * Loads properties.
     * @param props The properties to be loaded.
     */
    public void loadProperties(final Properties props) {
        if (props != null) {
            final Set<String> keys = props.stringPropertyNames();
            for (final String key : keys) {
                if (key.startsWith(KEY_PREFIX)) {
                    properties.setProperty(key, props.getProperty(key));
                }
            }
        }
    }

    /**
     * Loads the test properties from environment variables.
     */
    public void loadEnvironmentVariables() {
        final Map<String, String> envVars = System.getenv();
        final Set<String> keys = envVars.keySet();
        if (keys != null) {
            for (final String key : keys) {
                if (key.startsWith(KEY_PREFIX)) {
                    properties.setProperty(key, envVars.get(key));
                }
            }
        }
    }
    
    /**
     * Returns the property value for the specified key.
     * @param key The property key
     * @return The property value
     */
    public String getProperty(final String key) {
        return properties.getProperty(key);
    }

    /**
     * Returns the property value for the specified (otherwise a default value).
     * @param key The property key
     * @param defaultValue The default property value
     * @return The property value
     */
    public String getProperty(final String key, final String defaultValue) {
        return properties.getProperty(key, defaultValue);
    }

    /**
     * Gets the username.
     * @return The username
     */
    public String getUsername() {
        return getProperty(KEY_USERNAME);
    }

    /**
     * Gets the password.
     * @return The password
     */
    public String getPassword() {
        return getProperty(KEY_PASSWORD);
    }

    /**
     * Gets the domain.
     * @return The domain
     */
    public String getDomain() {
        return getProperty(KEY_DOMAIN);
    }

    /**
     * Gets the repository name.
     * @return The repository name
     */
    public String getRepository() {
        return getProperty(KEY_REPOSITORY);
    }

}
